- 建立统一成小端,虽然网络字节序是大端,但是目前主流的设备也就是X86是小端的,那些大端的机器同时也支持小端,像ARM、POWERPC都是支持小端的;
- 字节序一般是对数字而言的,要处理数字字节序的问题也很简单,不要使用系统默认的数字读入或读取方式读取数据(因为这样采用的是默认的字节序),而是自己通过程序将数字拆成大端或小端的数据,这样就保证了统一的字节序;
- 字节序的本质问题就是两个字节以及以上的类型值的问题,网络传输数据的时候是二进制流,数据发送时是什么样,接收时还是什么样,如果在socket两端的机器大小端相同或者没有两个字节以上的数据(就像字符串里都是单个字节组成的数据,但是如果struct里面包含了多个字节的数据就需要转换了),网络字节序便没什么用,只有socket两端的机器大小端不一样,它们对于二进制数据比如0x1234的理解才不一样,所以需要调用hton*那一系列的函数进行相应的转换才能得到正确的数据;
- 对于socket来说,它只认识byte[],socket负责把byte[]从源端运到目标端,至于byte[]怎么解析完全是业务层的事情;
为什么基于TCP的通讯程序需要进行封包和解包
TCP是一个流协议,所谓流就是没有界限的一串数据,大家可以想想河里的流水,是连成一片的,其间是没有分界线的,但一般通讯程序开发是需要定义一个个相互独立的数据包的,比如用于登录的数据包,用于注销的数据包。由于TCP流的特性以及网络状况,在进行数据传输时会出现以下几种情况:
假设我们连续调用两次send分别发送两端数据data1和data2,在接收端有以下几种接收情况:
- 先接收到data1,然后接收到data2;
- 先接收到data1的部分数据,然后接收到data1余下的部分以及data2的全部;
- 先接收到了data1的全部数据和data2的部分数据,然后接收到了data2的余下数据;
- 一次性接收到了data1和data2的全部数据。
对于第一种情况正是我们所需要的,不再做讨论,对于第二、三、四种情况就是“粘包”,就需要我们把接收到的数据进行拆包,拆成一个个独立的数据包,为了拆包就必须在发送端进行封包。
注意:对于UDP来说不存在拆包的问题,因为UDP是个“数据包”协议,也就是两段数据之间是有界限的,在接收端要么接收到一个完整的一段数据要么接收不到数据,不会少接收也不会多接收。
粘包原因
粘包可能会发生在发送端也可能会发生在接收端。
- 由Nagle算法造成的发送端的粘包:Nagle算法是一种改善网络传输效率的算法,当我们提交一段数据给TCP时,TCP并不会立即发送此段数据,而是等待一段时间,看看在等待期间是否还有要发送的数据,若有则会一次把这两段数据发送出去;
- 接收端接收不及时造成的接收端粘包:TCP会把接收到的数据存在自己的缓冲区中,然后通知应用层去读取数据,当应用层由于某些原因不能及时的把TCP的数据取出来,就会造成TCP缓冲区中存放了几段数据。
解决方法
利用底层的缓冲区进行拆包。对于阻塞socket来说,我们可以利用一个循环来接收包头长度的数据,然后解析出代表包体长度的那个变量,再用一个循环来接收包体长度的数据。
|
|